/*
** Cloth Simulation
** Author: Arturo Nereu
** Author: Diego Gurrusquieta
** 8 a 12 y 13:17
*/

#include <windows.h>
#include <GL/glut.h>
#include <GL/glui.h>

#include <iostream>
#include <fstream>
#include <vector>

#include <stdio.h>
#include "Wire.h"
#include "Light.h"
#include "Material.h"

#define MAX_RESOLUTION 80
#define MIN_RESOLUTION 20
#define RESOLUTION_DELTA 10

#define WIRE_SIZE 600

#define SPHERE_RADIUS 100
#define SPHERE_SLICES 20

#define CYLINDER_RADIUS 80
#define CYLINDER_HEIGHT 240
#define CYLINDER_SLICES 10

#define MIN_PARTICLES_PER_HAIR 1
#define MAX_PARTICLES_PER_HAIR 10

#define REFRESH_RATE 60

/********** User IDs for callbacks ********/
#define MESH_RESOLUTION_ID 100
#define TEXTURE_ENABLED_ID 200
#define SHOW_WIRE_FRAME_ID 201
#define FLAT_SHADE_ID 202
#define SHOW_PARTICLES_ID 203
#define ENABLE_LIGHT_ID 300
#define LIGHT_LEVEL_ID 301
#define LIGHT_RED_COMPONENT_ID 302
#define LIGHT_GREEN_COMPONENT_ID 303
#define LIGHT_BLUE_COMPONENT_ID 304
#define GRAVITY_CONSTANT_ID 400
#define GRAVITY_DIRECTION_ID 401
#define KS_ID 402
#define KD_ID 403
#define PARTICLE_RADIUS_ID 404
#define START_ID 500
#define PAUSE_ID 501
#define RESTART_ID 502
#define FIGURE_ID 600



// 全局变量
int lastX = 0;
int lastY = 0;
bool isDragging = false;
float rotationX = 0.0;
float rotationY = 0.0;
float centerX = 0.0;
float centerY = 0.0;
float centerZ = 0.0;
int resolution = 10; // 设置一个初始值，根据实际需求修改

void calculateCenter();
void display();
void mouse(int button, int state, int x, int y);
void motion(int x, int y);

GLUI *glui;
GLUI_Spinner *spinnerResolution;
GLUI_Button *buttonUpdate;
GLUI_Scrollbar *scrollbarTime;

int main_window;
GLUI_Spinner *spinnerTime;
GLUI_StaticText *textCurrentTime;
GLUI_Column *columnNodeInfo;
GLUI_StaticText *textNodeInfoX;
GLUI_StaticText *textNodeInfoY;
GLUI_StaticText *textNodeInfoZ;
GLUI_StaticText *textNodeInfoRotationX;
GLUI_StaticText *textNodeInfoRotationY;
GLUI_StaticText *textNodeInfoRotationZ;

int currentTime = 0;
// 定时器时间间隔（毫秒）
const int TIMER_INTERVAL = 1000; // 设置为1000ms，即1秒

// 定义时间滑条的最大值
const int MAX_TIME = 60;

static GLUI_StaticText *textNodeInfo;
GLUI_Rollout *infoRollout;

void calculateCenter() {
    // 计算图形的中心位置
    // 在这里添加计算中心位置的代码，例如遍历节点坐标，计算平均值等

    // 这里我们假设中心位置已知，可以根据您的实际情况来修改
    centerX = 35.0;
    centerY = 35.0;
    centerZ = 0.0;
}

struct Node {
    float x, y, z;
};

struct Element {
    int node1, node2;
};

std::vector<Node> nodes;
std::vector<Element> elements;

void readNodesFromFile(const char* filename) {
    std::ifstream file(filename);
    if (!file) {
        std::cerr << "Error opening file: " << filename << std::endl;
        return;
    }

    Node node;
    while (file >> node.x >> node.y >> node.z) {
        nodes.push_back(node);
    }

    file.close();
}

void readElementsFromFile(const char* filename) {
    std::ifstream file(filename);
    if (!file) {
        std::cerr << "Error opening file: " << filename << std::endl;
        return;
    }

    Element element;
    while (file >> element.node1 >> element.node2) {
        elements.push_back(element);
    }

    file.close();
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // 应用旋转变换
    glRotatef(rotationX, 1.0, 0.0, 0.0);
    glRotatef(rotationY, 0.0, 1.0, 0.0);

    // 设置透视投影
    double fovy = 60.0; // 视角的张角
    double aspect = 1.0; // 视口的宽高比
    double zNear = 1.0; // 近裁剪平面的距离
    double zFar = 1000.0; // 远裁剪平面的距离
    gluPerspective(fovy, aspect, zNear, zFar);



    // 设置视角位置和观察方向
    double eyeX = 100.0;
    double eyeY = 100.0;
    double eyeZ = 100.0; // 从正X轴偏移的位置
    double upX = 0.0;
    double upY = 1.0; // 摄像机的上方向设置为正Y轴方向
    double upZ = 0.0;
    gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);


    // 绘制小梁单元网格
    glColor3f(0.5, 0.5, 0.5); // 设置颜色为灰色
    for (const auto& element : elements) {
        const Node& node1 = nodes[element.node1 - 1]; // -1是因为节点编号从1开始
        const Node& node2 = nodes[element.node2 - 1];

        glBegin(GL_LINES);
        glVertex3f(node1.y*5, node1.z*5,node1.x*5);
        glVertex3f(node2.y*5, node2.z*5,node2.x*5);
        glEnd();
    }


    // 注意：确保在绘制图形时使用正确的深度函数
    glDepthFunc(GL_LESS); // 或其他适当的深度函数

    glFlush();
    glutSwapBuffers();
}

void mouse(int button, int state, int x, int y) {
    if (button == GLUT_LEFT_BUTTON) {
        if (state == GLUT_DOWN) {
            isDragging = true;
            lastX = x;
            lastY = y;
        }
        else if (state == GLUT_UP) {
            isDragging = false;
        }
    }
}

void motion(int x, int y) {
    if (isDragging) {
        //int deltaX = x - lastX;
        //int deltaY = y - lastY;
        //rotationX += deltaX * 0.1;
        //rotationY -= deltaY * 0.1; // 注意y方向的坐标系与OpenGL相反，所以要减去deltaY
        rotationX += (y - lastY) * 0.5;
        rotationY += (x - lastX) * 0.5;
        lastX = x;
        lastY = y;
        glutPostRedisplay(); // 重新绘制图形

    }
}

void autoUpdateNodesAndElements() {

    // 清空原有的节点和梁单元信息
    nodes.clear();
    elements.clear();

    readNodesFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\nodes.txt");
    readElementsFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\elements.txt");
}

void updateButtonCallback(int) {
    // 在此处理按钮点击事件
    // 读取txt文件中的节点坐标，更新网格图像

    // 读取节点坐标和梁单元信息
    readNodesFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\nodes.txt");
    readElementsFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\elements.txt");

    // 计算图形的中心位置
    calculateCenter();

    // 更新网格图像后，强制刷新显示
    glutPostRedisplay();
}

// GLUI滑条回调函数
void timeScrollCallback(int value) {
    currentTime = value;
    // 在此处理滑条值改变事件
    // 例如：根据currentTime更新节点坐标，并重绘图像

    // ...

    // 计算图形的中心位置
    calculateCenter();

    // 更新网格图像后，强制刷新显示
    glutPostRedisplay();
}



// GLUT定时器回调函数
void timer(int value) {
    // 定时器触发时执行的操作
    // 例如：更新节点坐标并重绘图像
    // 自动更新时间滑条的值
    currentTime += 1;
    if (currentTime > MAX_TIME) {
        currentTime = 0;
    }

    // 更新GLUI滑条的值
    scrollbarTime->set_int_val(currentTime);

    // 更新显示当前时间的文本
    std::string timeStr = "Time: " + std::to_string(currentTime);
    textCurrentTime->set_text(timeStr.c_str());

    // 在这个函数中，您可以实现读取txt文件中的节点坐标和梁单元信息，并进行相应的更新
    autoUpdateNodesAndElements();

    // 计算图形的中心位置
    calculateCenter();

    // 更新网格图像后，强制刷新显示
    glutPostRedisplay();

    // 设置下一次定时器触发的时间间隔（毫秒）
    glutTimerFunc(1000, timer, 0);// 设置为1000ms，即1秒
}

// GLUI旋转器回调函数
void resolutionSpinnerCallback(int value) {
    // 在此处理分辨率变化的事件
    // 例如：根据resolution更新节点坐标，并重绘图像

    // 清空之前的节点和梁单元信息
    nodes.clear();
    elements.clear();

    // 读取新的节点坐标和梁单元信息
    readNodesFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\nodes.txt");
    readElementsFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\elements.txt");

    // 计算图形的中心位置
    calculateCenter();

    // 更新网格图像后，强制刷新显示
    glutPostRedisplay();
}

void updateNodeInfo() {
    // 更新节点位移和旋转信息
    std::string nodeXStr = "0.01";
    std::string nodeYStr = "6.08E-6";
    std::string nodeZStr = "8.5E-6";
    std::string rotationXStr = "2.57E-7";
    std::string rotationYStr = "-2.65E-4";
    std::string rotationZStr = "-6.23E-6";

    // 更新静态文本控件的文本内容
    textNodeInfoX->set_text("Node info:");
    textNodeInfoX->set_text(("X: " + nodeXStr).c_str());
    textNodeInfoY->set_text(("Y: " + nodeYStr).c_str());
    textNodeInfoZ->set_text(("Z: " + nodeZStr).c_str());
    textNodeInfoRotationX->set_text(("RotationX: " + rotationXStr).c_str());
    textNodeInfoRotationY->set_text(("RotationY: " + rotationYStr).c_str());
    textNodeInfoRotationZ->set_text(("RotationZ: " + rotationZStr).c_str());

    glutPostRedisplay();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // 设置双缓冲模式
    glutInitWindowSize(800, 600);

    // 创建GLUI主窗口
    main_window = glutCreateWindow("Net plane");
    glui = GLUI_Master.create_glui_subwindow(main_window, GLUI_SUBWINDOW_RIGHT);

    // 创建分辨率面板和旋转器
    GLUI_Panel *resolutionPanel = glui->add_panel("Resolution");
    spinnerResolution = glui->add_spinner_to_panel(resolutionPanel, "Mesh resolution", GLUI_SPINNER_INT, &resolution, -1, resolutionSpinnerCallback);
    spinnerResolution->set_int_limits(MIN_RESOLUTION, MAX_RESOLUTION);

    // 创建更新按钮
    buttonUpdate = glui->add_button("Update", -1, updateButtonCallback);

    //创建时间滑条
    GLUI_Panel *timePanel = glui->add_panel("Time");
    scrollbarTime = new GLUI_Scrollbar(timePanel, "Current Time", GLUI_SCROLL_HORIZONTAL, &currentTime, -1, timeScrollCallback);
    scrollbarTime->set_int_limits(0, MAX_TIME);
    //timePanel->add_control(scrollbarTime);

    // 创建静态文本控件来显示当前时间
    textCurrentTime = new GLUI_StaticText(timePanel, "Time: 0"); // 初始显示时间为0

        // 创建静态文本控件来显示最大位移单元
    GLUI_StaticText *textMaxElement = glui->add_statictext("Max Displacement Element: 110");

        // 创建静态文本控件来显示最大位移单元
    GLUI_StaticText *textMaxNode = glui->add_statictext("Max Displacement Node: 361");

    // 创建静态文本控件来显示最大位移单元
    GLUI_StaticText *textMaxDisplacement = glui->add_statictext("Max Displacement: 0.01 m/s");

    // 创建一个列布局来显示节点位移和旋转
    textNodeInfoX = glui->add_statictext("Node info:");
    textNodeInfoX = glui->add_statictext("X: 0.0");
    textNodeInfoY = glui->add_statictext("Y: 0.0");
    textNodeInfoZ = glui->add_statictext("Z: 0.0");
    textNodeInfoRotationX = glui->add_statictext("RotationX: 0.0");
    textNodeInfoRotationY = glui->add_statictext("RotationY: 0.0");
    textNodeInfoRotationZ = glui->add_statictext("RotationZ: 0.0");

    updateNodeInfo();
    textNodeInfoX = glui->add_statictext("Load info");
    textNodeInfoRotationZ = glui->add_statictext("net load: 0 N");
    textNodeInfoRotationZ = glui->add_statictext("Max element tension: 0 N");


    // 启动GLUT定时器，每秒触发一次
    glutTimerFunc(1000, timer, 0); // 设置为1000ms，即1秒


    glClearColor(1.0, 1.0, 1.0, 1.0); // 设置背景色为白色

    glEnable(GL_DEPTH_TEST); // 启用深度测试，确保正确绘制3D场景

    // 读取节点坐标和梁单元信息
    readNodesFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\nodes.txt");
    readElementsFromFile("C:\\Users\\Administrator\\Desktop\\biye\\code\\github_download\\cloth_sim\\glut_project\\test_fortran\\input\\elements.txt");

    // 计算图形的中心位置
    calculateCenter();

    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);

    glutMainLoop();
    return 0;
}



/*

// 全局变量
int main_window;
GLUI *glui;
GLUI_Spinner *amplitude_spinner;
GLUI_Spinner *frequency_spinner;
GLUI_Spinner *speed_spinner;

float amplitude = 0.5;
float frequency = 1.0;
float phase = 0.0;
float speed = 1.0;

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(0.0, 0.0, 1.0); // 设置蓝色绘制颜色

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, 1.33, 1.0, 100.0); // 设置透视投影

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // 设置相机位置和观察点

    glPushMatrix();
    glRotatef(-45.0, 1.0, 0.0, 0.0); // 绕X轴旋转45度，使波形朝下观察
    glTranslatef(0.0, -5.0, 0.0); // 将波形移到视野中心

    glBegin(GL_LINE_STRIP);
    for (float x = -10.0; x <= 10.0; x += 0.1)
    {
        float y = amplitude * sin(frequency * x + phase);
        glVertex3f(x, y, 0.0); // 在三维坐标系中绘制波形
    }
    glEnd();

    glPopMatrix();

    glutSwapBuffers();
}

void update(int value)
{
    phase += speed * 0.01;
    glutPostRedisplay();
    glutTimerFunc(16, update, 0);
}

void controlCallback(int id)
{
    // 获取控件的值并更新全局变量
    amplitude = amplitude_spinner->get_float_val();
    frequency = frequency_spinner->get_float_val();
    speed = speed_spinner->get_float_val();

    // 重新绘制
    glutPostRedisplay();
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); // 启用深度缓冲区
    glutInitWindowSize(800, 600);
    main_window = glutCreateWindow("3D规则波图形界面");

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);

    // 创建GLUI
    glui = GLUI_Master.create_glui("Controls");
    amplitude_spinner = glui->add_spinner("Amplitude", GLUI_SPINNER_FLOAT, &amplitude, 0, controlCallback);
    amplitude_spinner->set_float_limits(0.1, 1.0);
    frequency_spinner = glui->add_spinner("Frequency", GLUI_SPINNER_FLOAT, &frequency, 1, controlCallback);
    frequency_spinner->set_float_limits(0.1, 5.0);
    speed_spinner = glui->add_spinner("Speed", GLUI_SPINNER_FLOAT, &speed, 2, controlCallback);
    speed_spinner->set_float_limits(0.1, 10.0);

    glui->set_main_gfx_window(main_window);

    glutDisplayFunc(display);
    glutTimerFunc(0, update, 0);

    glutMainLoop();
    return 0;
}
*/
